package top.hkyzf.study.j2se.syy.problem;

import org.junit.Test;

import java.nio.charset.Charset;
import java.util.*;

/**
 * @author 朱峰
 * @date 2021-5-22 0:47
 */
public class SongYy {

    /**
     * 第二题
     */
    @Test
    public void test2 () {
        // 1.输入
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一个字符串：");
        String next = scanner.next();

        // 2.转换
        StringBuilder sb = new StringBuilder();
        // 遍历字符串中的所有字符
        for(int i = 0; i < next.length(); i++) {
            // 获取每个位置的字符
            char ch = next.charAt(i);
            // 判断是否为大写
            if(Character.isUpperCase(ch)) {
                // 转小写
                sb.append(Character.toLowerCase(ch));
            } else {
                // 转大写
                sb.append(Character.toUpperCase(ch));
            }
        }

        // 3.输出
        System.out.println(sb.toString());
    }

    /**
     * 第三题
     */
    @Test
    public void test3 () {
        // 1.输入
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一个字符串：");
        String next = scanner.next();

        // 2.计算
        Map<Character, Integer> map = new HashMap<>();
        // 遍历字符串中的所有字符
        for(int i=0; i<next.length(); i++) {
            // 获取每个位置的字符
            char ch = next.charAt(i);
            Integer index = map.get(ch);
            if(index != null) {
                index = index + 1;
                map.put(ch, index);
            } else {
                map.put(ch, 1);
            }
        }

        // 3.遍历输出结果
        System.out.println("不同的字母有 " + map.size() + " 个");
        Set<Map.Entry<Character, Integer>> entrySet = map.entrySet();
        for (Map.Entry<Character, Integer> entry : entrySet) {
            System.out.println(entry.getKey() + " 字母有 " + entry.getValue() + " 个");
        }
    }

    /**
     * 第四题
     */
    @Test
    public void test4 () {
        // 1.输入
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一个句子：");
        String str = scanner.nextLine();
	    si(str);

    }

    /**
     * 将输入的句子每个单词首字母大写，第四题使用
     * @param str 输入的句子
     */
    private static void si(String str) {
	    String[] split = str.split(" ");
	    //按空格分隔成数组
	    for (int i = 0; i <split.length ; i++) {
	        String s2 = split[i].substring(0, 1).toUpperCase()+split[i].substring(1);
	        System.out.print(s2+" ");
	    }
	}

    /**
     * 第五题
     */
    @Test
    public void test5 () {
        // 1.输入
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一个 8 进制数：");
        String octNext = scanner.next();

        // 转换为10进制
        int anInt = Integer.parseInt(octNext, 8);
        System.out.println("十进制数：" + anInt);
        // 转换为2进制
        String binaryString = Integer.toBinaryString(anInt);
        System.out.println("二进制数：" + binaryString);
        // 转换为16进制
        String hexString = Integer.toHexString(anInt);
        System.out.println("十六进制数：" + hexString);
    }

    /**
     * 第六题
     * 这样转换不受 int 类型最长最大数限制
     */
    @Test
    public void test6 () {
        // 1.输入
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一个 16 进制数（0xFF 或 FF）：");
        String hexNext = scanner.next();

        // 将 0x替换掉
        if(hexNext.contains("0x")) {
            hexNext = hexNext.replace("0x", "");
        }
        // 判断长度是否为偶数位，不是则前面补 0
        if(hexNext.length() % 2 != 0) {
            hexNext = "0" + hexNext;
        }
        // 2.转换
        StringBuilder binStr = new StringBuilder();
        for (int i = 0; i < hexNext.length(); i+=2) {
            String temp = hexNext.substring(i, i+2);
            // 16 进制转换为 10 进制
            int anInt = Integer.parseInt(temp, 16);
            // 10 进制转换为 2 进制
            String binaryString = Integer.toBinaryString(anInt);
            // 前面补 0 到 8 位（ 2 位 16 进制对应 8 位 2 进制数）
            String string = fillZeroBeforeString(binaryString, 8);
            binStr.append(string);
        }
        // 3.输出
        System.out.println("对应的二进制数为：" + binStr.toString());
    }

    /**
     * 字符串前补 0 到指定长度，第六题使用
     * @param str 给定字符串
     * @param length 所需长度
     * @return 将给定字符串前补 0 到所需长度
     */
    private static String fillZeroBeforeString(String str, int length) {
        if (str.length() < length) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < length - str.length(); i++) {
                sb.append("0");
            }
            sb.append(str);
            return sb.toString();
        } else {
            return str;
        }
    }

    /**
     * 第七题
     */
    @Test
    public void test7 () {
        // 定义初始字符串
        String aToS = "abcdefghijklmnopqrs";
        // 重复拼接 52 次
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < 52; i++) {
            sb.append(aToS);
        }
        System.out.println("字符串长度为：" + sb.length());

        // 长度为 1 结束循环
        do {
            // 删除奇数位字母
            for (int i = 1; i <= sb.length(); i++) {
                sb.deleteCharAt(i - 1);
                System.out.println(sb);
            }
        } while (sb.length() != 1);

        System.out.println("最后的一个字母为：" + sb.toString());
    }

    /**
     * 第八题
     */
    @Test
    public void test8 () {
        // 1.输入
//        Scanner scanner = new Scanner(System.in);
//        System.out.println("请输入是否含有数字：");
//        Boolean hasNum = scanner.nextBoolean();
//        System.out.println("请输入是否含有大写：");
//        Boolean hasUpper = scanner.nextBoolean();
//        System.out.println("请输入是否含有小写：");
//        Boolean hasLower = scanner.nextBoolean();
//        System.out.println("请输入字符否可重复：");
//        Boolean repeat = scanner.nextBoolean();
//        System.out.println("请输入验证码长度：");
//        Integer length = scanner.nextInt();

        // 是否有数字
        boolean hasNum = true;
        // 是否有大写
        boolean hasUpper = true;
        // 是否有小写
        boolean hasLower = true;
        // 是否可重复
        boolean repeat = true;
        // 验证码长度
        int length = 5;

        String captcha = getCaptcha(hasNum, hasUpper, hasLower, repeat, length);
        System.out.println("验证码为：" + captcha);
    }

    /**
     * 生成验证码的方法，第八题使用
     * @param hasNum 是否包含数字
     * @param hasUpper 是否包含大写字母
     * @param hasLower 是否包含小写字母
     * @param repeat 字符是否可重复
     * @param length 验证码长度（如果字符不可重复，不可大于有效字符长度）
     * @return 返回验证码字符串
     */
    private static String getCaptcha(boolean hasNum, boolean hasUpper, boolean hasLower, boolean repeat, int length) {
        // 0-9 字符
        char [] numArr = {48,49,50,51,52,53,54,55,56,57};
        // A-Z 字符
        char [] upperArr = {65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90};
        // a-z 字符
        char [] lowerArr = {97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122};
        // 填装最终使用的字符
        char [] finalArr = new char[numArr.length + upperArr.length + lowerArr.length];
        // 记录最终使用的字符有效长度
        int finalLength = 0;
        // 判断是否有数字
        if(hasNum){
            System.arraycopy(numArr, 0, finalArr, 0, numArr.length);
            finalLength += numArr.length;
        }
        // 判断是否有大写字母
        if(hasUpper){
            System.arraycopy(upperArr, 0, finalArr, hasNum ? numArr.length : 0, upperArr.length);
            finalLength += upperArr.length;
        }
        // 判断是否有小写字母
        if(hasLower){
            System.arraycopy(lowerArr, 0, finalArr, (hasNum ? numArr.length : 0) + (hasUpper ? upperArr.length : 0), lowerArr.length);
            finalLength += lowerArr.length;
        }

        // 校验长度是否合法
        if(!repeat && length > finalLength) {
            throw new IllegalArgumentException("输入长度不合法，字符不可重复，但是验证码长度过长。");
        }
        // 生产验证码
        StringBuilder result = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            // 字符是否可重复
            if(repeat) {
                //产生 0 到数组实际长度的随机值
                int index = random.nextInt(finalLength);
                //在目标数组中获取下标为 index 的字符
                char ch = finalArr[index];
                //将 ch 放入到 StringBuilder 中去
                result.append(ch);
            } else {
                //产生 0 到数组实际长度的随机值
                int index = random.nextInt(finalLength);
                //在目标数组中获取下标为 index 的字符
                char ch = finalArr[index];
                //将 ch 放入到 StringBuilder 中去
                result.append(ch);

                // 移除当前字符
                for (int j = index; j < finalLength; j++) {
                    // 此判断防止角标越界异常
                    if(j != finalArr.length -1) {
                        finalArr[j] = finalArr[j+1];
                    }
                }
                finalLength --;
            }
        }
        return result.toString();
    }
}
